#include "../logs/util.hpp"
#include "../logs/level.hpp"
#include "../logs/message.hpp"
#include "../logs/format.hpp"
#include "../logs/sink.hpp"
#include "../logs/logger.hpp"
#include "../logs/buffer.hpp"
#include "../logs/clxlog.h"

void util_test() {
    std::cout << clxlog::util::Data::now() << std::endl;
    
    std::string pathname = "./abc/bcd/a.txt";
    if (clxlog::util::File::exists(pathname)) {
        std::cout << pathname << " exists" << std::endl;
    } else {
        std::cout << "pathname" << " no exists" << std::endl;
    }

    std::string file_path = clxlog::util::File::path(pathname);
    std::cout << "file in the " << file_path << std::endl;

    clxlog::util::File::createDirectory(clxlog::util::File::path(pathname));
}

void level_test() {
    std::cout << clxlog::LogLevel::toString(clxlog::LogLevel::value::DEBUG) << std::endl;
    std::cout << clxlog::LogLevel::toString(clxlog::LogLevel::value::INFO) << std::endl;
    std::cout << clxlog::LogLevel::toString(clxlog::LogLevel::value::WARN) << std::endl;
    std::cout << clxlog::LogLevel::toString(clxlog::LogLevel::value::ERROR) << std::endl;
    std::cout << clxlog::LogLevel::toString(clxlog::LogLevel::value::FATAL) << std::endl;
    std::cout << clxlog::LogLevel::toString(clxlog::LogLevel::value::OFF) << std::endl;
    std::cout << clxlog::LogLevel::toString(clxlog::LogLevel::value::UNKNOW) << std::endl;
}

std::string format_test() {

    clxlog::LogMsg msg(clxlog::LogLevel::value::INFO, __LINE__, __FILE__, "root", "格式化功能测试");
    clxlog::Formatter fmt;
    // clxlog::Formatter fmt("%g%gabc%%abc[%d{%H:%M:%S}] %m%n");
    std::string str = fmt.format(msg);
    std::cout << str << std::endl;
    return str;
}

void sink_test() {
    std::string str = format_test();
    clxlog::LogSink::ptr stdout_lsp = clxlog::SinkFactory::create<clxlog::StdoutSink>();
    clxlog::LogSink::ptr file_lsp = clxlog::SinkFactory::create<clxlog::FileSink>("./filelog/log.txt");
    clxlog::LogSink::ptr roll_file_lsp = clxlog::SinkFactory::create<clxlog::RollBySizeSink>("./rollfilelog/roll-", 1024 * 1024);
    stdout_lsp->log(str.c_str(), str.size());
    file_lsp->log(str.c_str(), str.size());
    size_t cursize = 0;
    size_t count = 0;
    while (cursize < 1024 * 1024 * 10) {
        std::string tmp = std::to_string(count++) + str;
        roll_file_lsp->log(tmp.c_str(), tmp.size());
        cursize += tmp.size();
    }
}


// 落地扩展，以时间作为滚动的依据的滚动文件落地方式
enum class TimeGap {
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_DAY
};

class RollByTimeSink : public clxlog::LogSink {
    public:
        RollByTimeSink(const std::string &basename, TimeGap gap_type) 
            : _basename(basename), _cur_gap(0)
        {
            switch(gap_type) {
                case TimeGap::GAP_SECOND : _gap_size = 1  ;             break;
                case TimeGap::GAP_MINUTE : _gap_size = 60 ;             break;
                case TimeGap::GAP_HOUR   : _gap_size = 60 * 60 ;        break;
                case TimeGap::GAP_DAY    : _gap_size = 60 * 60 * 24 ;   break;
            }
            _cur_gap = clxlog::util::Data::now() / _gap_size;
            std::string filename = createNewFile();
            clxlog::util::File::createDirectory(clxlog::util::File::path(filename));
            _ofs.open(filename, std::ios::binary | std::ios::app);
            assert(_ofs.good());
        }

        void log(const char* data, size_t len) {
            time_t cur = clxlog::util::Data::now();
            if ((cur / _gap_size) != _cur_gap) {
                _ofs.close();
                std::string filename = createNewFile();
                _ofs.open(filename, std::ios::binary | std::ios::app);
                assert(_ofs.good());
            }
            _ofs.write(data, len);
            assert(_ofs.good());
        }

    private:
        std::string createNewFile() {
            time_t t = clxlog::util::Data::now();
            struct tm lt;
            localtime_r(&t, &lt);
            std::stringstream filename;
            filename << _basename;
            filename << (lt.tm_year + 1900);
            filename << "-";
            filename << (lt.tm_mon + 1);
            filename << "-";
            filename << lt.tm_mday;
            filename << " ";
            filename << lt.tm_hour;
            filename << ":";
            filename << lt.tm_min;
            filename << ":";
            filename << lt.tm_sec;
            filename << ".log";
            return filename.str();
        }
    private:
        std::string _basename;
        size_t _cur_gap;
        size_t _gap_size;
        std::ofstream _ofs;
};

void expansion_sink_test() {
    std::string str = format_test();
    clxlog::LogSink::ptr roll_time_lsp = clxlog::SinkFactory::create<RollByTimeSink>("./roll_time_file_log/roll-time-", TimeGap::GAP_SECOND);
    size_t count = 0;
    while (count < 3) {
        std::string tmp = std::to_string(count++) + str;
        roll_time_lsp->log(tmp.c_str(), tmp.size());
        sleep(1);
    }
}

void logger_test() {
    std::string logger_name = "sync_logger";
    clxlog::LogLevel::value limit_level = clxlog::LogLevel::value::DEBUG;
    clxlog::Formatter::ptr fmt(new clxlog::Formatter());
    clxlog::LogSink::ptr stdout_lsp = clxlog::SinkFactory::create<clxlog::StdoutSink>();
    clxlog::LogSink::ptr file_lsp = clxlog::SinkFactory::create<clxlog::FileSink>("./filelog/log.txt");
    clxlog::LogSink::ptr roll_file_lsp = clxlog::SinkFactory::create<clxlog::RollBySizeSink>("./rollfilelog/roll-", 1024 * 1024);
    std::vector<clxlog::LogSink::ptr> sinks = { stdout_lsp, file_lsp, roll_file_lsp };

    clxlog::Logger::ptr logger_ptr(new clxlog::SynchLogger(logger_name, limit_level, fmt, sinks));

    logger_ptr->debug(__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->info (__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->warn (__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->error(__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->fatal(__FILE__, __LINE__, "%s", "测试日志");

    size_t cursize = 0, count = 0;
    std::string str = "测试日志";
    while (cursize < 1024 * 1024 * 10) {
        logger_ptr->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
        cursize += 20;
    }
}

void build_synch_logger_test() {
    clxlog::LoggerBuilder::ptr builder(new clxlog::LocalLoggerBuilder());
    builder->buildLoggerType(clxlog::LoggerType::LOGGER_SYNCH);
    builder->buildLoggerLevel(clxlog::LogLevel::value::WARN);
    builder->buildLoggerName("clx_synch_logger");
    builder->buildLoggerFormatter("%m%n");
    builder->buildSink<clxlog::StdoutSink>();
    builder->buildSink<clxlog::FileSink>("./file_log/test.log");
    builder->buildSink<clxlog::RollBySizeSink>("./roll_file_log/roll-", 1024 * 1024);
    clxlog::Logger::ptr logger_ptr = builder->build();
    
    logger_ptr->debug(__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->info (__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->warn (__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->error(__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->fatal(__FILE__, __LINE__, "%s", "测试日志");

    size_t cursize = 0, count = 0;
    std::string str = "测试日志";
    while (cursize < 1024 * 1024 * 10) {
        logger_ptr->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
        cursize += 20;
    }
}

void buffer_test() {
    std::ifstream ifs("./file_log/test.log", std::ios::binary);
    if (ifs.is_open() == false) exit(-1);
    ifs.seekg(0, std::ios::end);   // 读写文职跳转到文件末尾
    size_t fsize = ifs.tellg();    // 获取当前当前位置相比于起始位置的偏移量
    ifs.seekg(0, std::ios::beg);   // 重新跳到起始位置
    std::string body;
    body.resize(fsize);
    ifs.read(&body[0], fsize);
    if (ifs.good() == false) { std::cout << "read error \n" << std::endl; exit(-1); }
    ifs.close();

    std::cout << fsize << std::endl;
    clxlog::Buffer buffer;
    for (int i = 0; i < body.size(); i++) {
        buffer.push(&body[i], 1);
    }
    std::cout << buffer.readAbleSize() << std::endl;
    
    int need_read_size = buffer.readAbleSize();
    std::ofstream ofs("./file_log/tmp.log", std::ios::binary);
    for (int i = 0; i < need_read_size; i++) {
        ofs.write(buffer.begin(), 1);
        if (ofs.good() == false) { std::cout << "wirte error ! " << std::endl; exit(-1); }
        buffer.moveReader(1);
    }
    ofs.close();
}

void build_asynch_logger_test() {
    clxlog::LoggerBuilder::ptr builder(new clxlog::LocalLoggerBuilder());
    builder->buildLoggerType(clxlog::LoggerType::LOGGER_ASYNCH);
    builder->buildLoggerLevel(clxlog::LogLevel::value::WARN);
    builder->buildLoggerName("clx_asynch_logger");
    builder->buildLoggerFormatter("%m%n");
    builder->buildSink<clxlog::StdoutSink>();
    builder->buildSink<clxlog::FileSink>("./file_log/test.log");
    builder->buildSink<clxlog::RollBySizeSink>("./roll_file_log/roll-", 1024 * 1024);
    clxlog::Logger::ptr logger_ptr = builder->build();

    logger_ptr->debug(__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->info (__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->warn (__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->error(__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->fatal(__FILE__, __LINE__, "%s", "测试日志");

    size_t cursize = 0, count = 0;
    std::string str = "测试日志";
    while (cursize < 1024 * 1024) {
        logger_ptr->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
        cursize += 20;
    }
}

void logger_manager_test_log() {
    clxlog::LoggerBuilder::ptr builder(new clxlog::GlobalLoggerBuilder());
    builder->buildLoggerType(clxlog::LoggerType::LOGGER_ASYNCH);
    builder->buildLoggerLevel(clxlog::LogLevel::value::WARN);
    builder->buildLoggerName("clx_asynch_logger");
    builder->buildLoggerFormatter("%m%n");
    builder->buildSink<clxlog::StdoutSink>();
    builder->buildSink<clxlog::FileSink>("./file_log/test.log");
    builder->buildSink<clxlog::RollBySizeSink>("./roll_file_log/roll-", 1024 * 1024);
    builder->build();

    clxlog::Logger::ptr logger_ptr = clxlog::LoggerManager::getInstance().getLogger("clx_asynch_logger");
    logger_ptr->debug(__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->info (__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->warn (__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->error(__FILE__, __LINE__, "%s", "测试日志");
    logger_ptr->fatal(__FILE__, __LINE__, "%s", "测试日志");

    size_t count = 0;
    std::string str = "测试日志";
    while (count < 1e5 * 5) {
        logger_ptr->fatal(__FILE__, __LINE__, "测试日志-%d", count++);
    }
}

void clxlog_test() {
    clxlog::LoggerBuilder::ptr builder(new clxlog::GlobalLoggerBuilder());
    builder->buildLoggerType(clxlog::LoggerType::LOGGER_ASYNCH);
    builder->buildLoggerLevel(clxlog::LogLevel::value::WARN);
    builder->buildLoggerName("clx_asynch_logger");
    builder->buildLoggerFormatter("[%c][%f:%l]%m%n");
    builder->buildSink<clxlog::StdoutSink>();
    builder->buildSink<clxlog::FileSink>("./file_log/test.log");
    builder->buildSink<clxlog::RollBySizeSink>("./roll_file_log/roll-", 1024 * 1024);
    builder->build();

    clxlog::Logger::ptr logger_ptr = clxlog::LoggerManager::getInstance().getLogger("clx_asynch_logger");

    // logger_ptr->debug("%s", "测试日志");
    // logger_ptr->info ("%s", "测试日志");
    // logger_ptr->warn ("%s", "测试日志");
    // logger_ptr->error("%s", "测试日志");
    // logger_ptr->fatal("%s", "测试日志");

    // size_t count = 0;
    // while (count < 1e5 * 5) {
    //     logger_ptr->fatal(测试日志-%d", count++);
    // }

    DEBUG("%s", "测试日志");
    INFO("%s", "测试日志");
    WARN("%s", "测试日志");
    ERROR("%s", "测试日志");
    FATAL("%s", "测试日志");

    size_t count = 0;
    while (count < 1e5 * 5) {
        FATAL("测试日志-%d", count++);
    }
}

void demo() {
    clxlog::LoggerBuilder::ptr builder(new clxlog::GlobalLoggerBuilder());
    builder->buildLoggerLevel(clxlog::LogLevel::value::DEBUG);
    builder->buildLoggerName("clx_synch_logger");
    builder->build();
    clxlog::Logger::ptr logger_ptr = clxlog::LoggerManager::getInstance().getLogger("clx_synch_logger");

    INFO("%s", "测试开始");

    DEBUG("%s", "测试日志");
    INFO("%s", "测试日志");
    WARN("%s", "测试日志");
    ERROR("%s", "测试日志");
    FATAL("%s", "测试日志");

    INFO("%s", "测试完毕");

}




int main(){
    // format_test();
    // sink_test();
    // expansion_sink_test();
    // logger_test();
    // build_synch_logger_test();
    // buffer_test();
    // build_asynch_logger_test();
    // logger_manager_test_log();
    // clxlog_test();
    demo();
    return 0;
}
